library MyKu;

import 'dart:math';

const MyName = "Chris";

num Max(num a, num b) {
  return a > b ? a : b;
}

void test1() {
  var name = 'Voyager I';
  var year = 1977;
  var antennaDiameter = 3.7;
  var flybyObjects = ['Jupiter', 'Saturn', 'Uranus', "neptune"];
  var image = {
    'tag': ['saturn'],
    'url': '//path/to/saturn.jpg'
  };

  print(name is String);

  print("这个类型:${image is dynamic}");

  print("结果:${-0 == 0}");

  if (year >= 2001) {
    print('21st century');
  } else if (year >= 1901) {
    print('20th century');
  }

  for (var obj in flybyObjects) {
    print(obj);
  }

  for (int moth = 1; moth <= 12; ++moth) {
    print(moth);
  }

  while (year < 2016) {
    ++year;
    print("结果$year");
  }
}

int fibonacci(int n) {
  if (n == 0 || n == 1) return n;
  return fibonacci(n - 1) + fibonacci(n - 2);
}

class Rectangle {
  num left, top, _width, _height;

  Rectangle(this.left, this.top, num width, num height)
      : this._width = width,
        this._height = height;

  set right(num value) => left = value - _width;

  set bottom(num value) => top = value - _height;

  get square => _width * _height;
}

class Animal {
  Animal() {
    print("Im a Animal");
  }
}

class Dog extends Animal {
  Dog() {
    print("Im a dog");
  }
}

class Cat extends Animal {
  Cat() {
    print("Im a Cat");
  }
}

//类变量实际上就是static修饰的变量，属于类的作用域范畴；顶层变量就是定义的变量不在某个具体类体内，而是处于整个代码文件中，相当于文件顶层，和顶层函数差不多意思。static变量
// 更多人愿意把它称为静态变量，但是在Dart中静态变量不仅仅包括static变量还包括顶层变量。

//其实对于类变量和顶层变量的访问都还是通过调用它的访问器函数来实现的，但是类变量和顶层变量有点特殊，它们是延迟初始化的，在getter函数第一次被调用时类变量或顶层变量才执行
// 初始化，也即是第一次引用类变量或顶层变量的时候。如果类变量或顶层变量没有被初始化默认值还是null.

//注意,这里变量不定义在任何具体类体内，所以这个animal是一个顶层变量。
//虽然看似创建了Cat对象，但是由于顶层变量延迟初始化的原因，这里根本就没有创建Cat对象
Animal cat = Cat();

//顶层变量是具有延迟初始化过程，所以Cat对象并没有创建，因为整个代码执行中并没有去访问animal，所以无法触发第一次getter函数，也就导致Cat对象没有创建，直接表现是根本就不会
// 输出I'm a Cat!这句话。这就是为什么顶层变量是延迟初始化的原因，static变量同理。

//在dart有些对象是在编译期就可以计算的常量，所以在dart中支持常量对象的定义，常量对象的创建需要使用 const 关键字。常量对象的创建也是调用类的构造函数，但是注意必须是常量构造函数，
// 该构造函数是用 const 关键字修饰的。常量构造函数必须是数字、布尔值或字符串，此外常量构造函数不能有函数体，但是它可以有初始化列表。
class Point {
  final num x, y;

  const Point(this.x, this.y); //常量构造函数，使用const关键字且没有函数体
  const Point.withX(double x) : this(x, 0); //注意这里使用this重定向到Point(double x, double y)主构造函数中。
  const Point.withY(double y) : this(0, y); //注意这里使用this重定向到Point(double x, double y)主构造函数中。

//  final double distance;
//
//  const Point.withDistance(this.distance);
//
//  const Point(double x, double y) :this.withDistance(sqrt(x * x + y * y));//注意:这里是主构造函数重定向到命名构造函数withDistance中。
  static double distance(Point p1, Point p2) {
    var dx = p1.x - p2.x;
    var dy = p1.y - p2.y;
    return sqrt(dx * dx + dy * dy);
  }
}

class Point3D extends Point {
  double z;

  Point3D(a, b, c)
      : z = c / 2,
        super(a, b);
}

class Logger {
  //实例属性
  final String name;
  bool mute = false;

  //_cache is library-private, thanks to the _ in front of its name.
  static final Map<String, Logger> _cache = <String, Logger>{}; //类属性

  Logger._internal(this.name);

  //有点对象池的味道
  factory Logger(String name) {
    //使用factory关键字声明工厂构造行数
    if (_cache.containsKey(name)) {
      //使用factory关键字声明工厂构造函数，
      return _cache[name]; //返回缓存已经创建实例
    } else {
      final logger = Logger._internal(name); //new 一个新Logger
      _cache[name] = logger; //把这个对象放到缓存中
      return logger; //注意: 最后返回这个新创建的对象
    }
  }

  void log(String msg) {
    if (!mute) print(msg);
  }
}

abstract class Person {
  String name();

  get age;
}

abstract class Speaking {
  //虽然定义的是抽象类，但是隐含地定义接口Speaking
  String speak();
}

abstract class Writing {
  //虽然定义的是抽象类，但是隐含地定义接口Writing
  String write();
}

class Student extends Person implements Speaking, Writing {
  @override
  String name() {
    // TODO: implement name
    return null;
  }

  @override
  // TODO: implement age
  get age => null;

  @override
  String speak() {
    // TODO: implement speak
    return null;
  }

  @override
  String write() {
    // TODO: implement write
    return null;
  }
}
